import { Emitter, Event } from '../../utils';

import {
  ITerminalApiService,
  ITerminalController,
  ITerminalExitEvent,
  ITerminalExternalClient,
  ITerminalGroupViewService,
  ITerminalInfo,
  ITerminalInternalService,
  ITerminalTitleChangeEvent,
  TerminalOptions,
} from '../common';

/**
 * 终端 API 服务实现，负责终端的创建、管理、事件分发等
 */
export class TerminalApiService implements ITerminalApiService {
  private _onDidOpenTerminal = new Emitter<ITerminalInfo>(); // 终端打开事件
  private _onDidCloseTerminal = new Emitter<ITerminalExitEvent>(); // 终端关闭事件
  private _onDidTerminalTitleChange = new Emitter<ITerminalTitleChangeEvent>(); // 终端标题变更事件
  private _onDidChangeActiveTerminal = new Emitter<string>(); // 活动终端变更事件

  readonly onDidOpenTerminal: Event<ITerminalInfo> =
    this._onDidOpenTerminal.event;
  readonly onDidCloseTerminal: Event<ITerminalExitEvent> =
    this._onDidCloseTerminal.event;
  readonly onDidTerminalTitleChange: Event<ITerminalTitleChangeEvent> =
    this._onDidTerminalTitleChange.event;
  readonly onDidChangeActiveTerminal: Event<string> =
    this._onDidChangeActiveTerminal.event;

  private controller: ITerminalController;
  private view: ITerminalGroupViewService;
  private service: ITerminalInternalService;

  constructor(
    controller: ITerminalController,
    view: ITerminalGroupViewService,
    service: ITerminalInternalService
  ) {
    this.controller = controller;
    this.view = view;
    this.service = service;

    // 监听 controller 的事件并转发
    this.controller.onDidOpenTerminal((info) => {
      this._onDidOpenTerminal.fire(info);
    });

    this.controller.onDidCloseTerminal((e) => {
      this._onDidCloseTerminal.fire(e);
    });

    this.controller.onDidTerminalTitleChange((e) => {
      this._onDidTerminalTitleChange.fire(e);
    });

    this.controller.onDidChangeActiveTerminal((id) => {
      this._onDidChangeActiveTerminal.fire(id);
    });
  }

  /**
   * 获取所有终端信息
   */
  get terminals() {
    return Array.from(this.controller.clients.values()).map((v) => ({
      id: v.id,
      name: v.name,
      isActive: this.view.currentWidgetId.get() === v.id,
    }));
  }

  /**
   * 创建终端
   * @param options 终端选项
   * @param id 可选 id
   */
  async createTerminal(
    options: TerminalOptions,
    id?: string
  ): Promise<ITerminalExternalClient> {
    const client =
      await this.controller.createTerminalWithWidgetByTerminalOptions({
        terminalOptions: options,
        id,
      });

    // 封装外部终端对象
    const external = {
      get id() {
        return client.id;
      },
      get name() {
        return client.name;
      },
      get processId() {
        return client.pid;
      },
      show: (preserveFocus = true) => {
        const widget = client.widget;
        this.view.selectWidget(widget.id);
        this.controller.showTerminalPanel();

        if (!preserveFocus) {
          setTimeout(() => client.focus());
        }
      },
      hide: () => {
        this.controller.hideTerminalPanel();
      },
      dispose: () => {
        this.view.removeWidget(client.widget.id);
        this.controller.clients.delete(client.id);
      },
    };

    await client.attached.promise;

    external.show();

    return external;
  }

  /**
   * 获取终端进程 id
   * @param sessionId 终端 session id
   */
  async getProcessId(sessionId: string) {
    const client = this.controller.clients.get(sessionId);
    if (!client) {
      return;
    }
    return client.pid;
  }

  /**
   * 向终端发送文本
   * @param sessionId 终端 session id
   * @param text 文本内容
   * @param addNewLine 是否自动添加换行
   */
  sendText(sessionId: string, text: string, addNewLine = true) {
    this.service.sendText(sessionId, `${text}${addNewLine ? '\r' : ''}`);
  }

  /**
   * 显示指定终端
   * @param sessionId 终端 session id
   * @param preserveFocus 是否保留焦点
   */
  showTerm(sessionId: string, preserveFocus = true) {
    const client = this.controller.clients.get(sessionId);
    if (!client) {
      return;
    }
    const widget = client.widget;
    this.view.selectWidget(widget.id);
    this.controller.showTerminalPanel();
    if (!preserveFocus) {
      setTimeout(() => client.focus());
    }
  }

  /**
   * 隐藏指定终端
   * @param sessionId 终端 session id
   */
  hideTerm(sessionId: string) {
    const client = this.controller.clients.get(sessionId);
    if (!client) {
      return;
    }
    this.controller.hideTerminalPanel();
  }

  /**
   * 移除指定终端
   * @param sessionId 终端 session id
   */
  removeTerm(sessionId: string) {
    const client = this.controller.clients.get(sessionId);
    if (!client) {
      return;
    }
    this.view.removeWidget(client.widget.id);
    this.controller.clients.delete(sessionId);
  }
}
